// Helper for generating C source and header files.

'use strict';

const { assert } = require('./assert');
const { cCommentEscape, cIntEncode } = require('./cquote');

function GenerateC() {
    this.data = [];
    this.wrapColumn = 76;
}

// Emit raw text (without automatic newline).
GenerateC.prototype.emitRaw = function emitRaw(rawText) {
    this.data.push(rawText);
};

// Emit a raw line (with automatic newline).
GenerateC.prototype.emitLine = function emitLine(text) {
    this.data.push(text + '\n');
};

// Emit an 'automatically generated by...' header.
GenerateC.prototype.emitAutogenHeader = function emitAutogenHeader(autogenBy) {
    this.emitLine('/*');
    this.emitLine(' *  Automatically generated by ' + autogenBy + ', do not edit!');
    this.emitLine(' */');
    this.emitLine('');
};

// Emit a C define with an optional comment.  Caller must escape
// value if necessary.
GenerateC.prototype.emitDefine = function emitDefine(name, value, comment) {
    assert(typeof value === 'number' || typeof value === 'string');
    if (typeof comment === 'undefined') {
        this.emitLine('#define ' + name + ' ' + value);
    } else {
        this.emitLine('#define ' + name + ' ' + value + '  /* ' + cCommentEscape(comment) + ' */');
    }
};

// Emit an array as a C array.
GenerateC.prototype.emitArray = function emitArray(data, opts) {
    var tableName = opts.tableName;
    var typeName = opts.typeName;
    var visibility = opts.visibility;
    var useConst = opts.useConst;
    var useCast = opts.useCast;
    var initLine = [];

    if (typeof visibility !== 'undefined') {
        initLine.push(visibility);
    }
    if (useConst) {
        initLine.push('const');
    }
    initLine.push(typeName);
    initLine.push(tableName + '[' + data.length + ']');
    this.emitLine(initLine.join(' ') + ' = {');

    var line = '';
    data.map((v) => {
        assert(typeof v === 'number');
        return cIntEncode(v);
    }).forEach((v, idx) => {
        let last = (idx == data.length - 1);
        let t;
        if (useCast) {
            t = '(' + typeName + ')' + v + (last ? '' : ',');
        } else {
            t = v + (last ? '' : ',');
        }
        if (line.length + t.length >= this.wrapColumn) {
            this.emitLine(line);
            line = t;
        } else {
            line += t;
        }
    });
    if (line !== '') {
        this.emitLine(line);
    }

    this.emitLine('};');
};

// Get the entire file as a string.
GenerateC.prototype.getString = function getString() {
    var res = this.data.join('');
    if (!res.endsWith('\n')) {
        return res + '\n';
    }
    return res;
};

exports.GenerateC = GenerateC;
